package com.zero.manage.web.config.shiro;

import cn.hutool.core.util.StrUtil;
import com.zero.manage.web.components.dto.SysUserDto;
import com.zero.manage.web.components.service.SysUserService;
import com.zero.manage.web.jwt.JwtToken;
import io.gitee.zerowsh.config.RedisUtil;
import io.gitee.zerowsh.constant.ToolConstant;
import io.gitee.zerowsh.enums.ResultEnums;
import io.gitee.zerowsh.enums.ToolEnums;
import io.gitee.zerowsh.util.JwtUtil;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.Objects;

/**
 * 自定义shiro规则
 */
public class MyRealm extends AuthorizingRealm {
    @Autowired
    @Lazy
    private SysUserService sysUserService;

    /**
     * 大坑！，必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof JwtToken;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取登录用户信息
        String name = JwtUtil.getClaim(principals.toString(), ToolConstant.MAME);
        //用户的角色，及权限进行绑定,这里只绑定权限,只通过权限来控制
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addStringPermissions(sysUserService.getPowerList(name));
        return simpleAuthorizationInfo;
    }

    //验证用户登录信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String jwtToken = (String) token.getCredentials();
//        String jwtToken = (String) token.getPrincipal();
        // 解密获得account，用于和数据库进行对比
        String name = JwtUtil.getClaim(jwtToken, ToolConstant.MAME);
        // 帐号为空
        if (StrUtil.isBlank(name)) {
            throw new AuthenticationException("Token中帐号为空(The account in Token is empty.)");
        }
        SysUserDto sysUserDto = sysUserService.getUserInfoByName(name);
        if (Objects.isNull(sysUserDto)) {
            throw new AuthenticationException(ResultEnums.USER_NOT_EXIST.getMsg());
        }

        if (Objects.equals(sysUserDto.getState(), ToolEnums.StateEnums.DISABLE)) {
            throw new AuthenticationException(ResultEnums.USER_DISABLE.getMsg());
        }

        // 开始认证，要AccessToken认证通过，且Redis中存在RefreshToken，且两个Token时间戳一致
        // 获取RefreshToken的时间戳
        String refreshTokenTime = RedisUtil.getStr(String.format(ToolConstant.REFRESH_ACCESS_TOKEN_PREFIX, name));
        //解析token存入时间
        String claim = JwtUtil.getClaim(jwtToken, ToolConstant.CURRENT_TIME_MILLIS);
        // 获取AccessToken时间戳，与RefreshToken的时间戳对比
        if (Objects.equals(refreshTokenTime, claim)) {
            return new SimpleAuthenticationInfo(jwtToken, jwtToken, "userRealm");
        }
        throw new AuthenticationException("Token已过期(Token expired or incorrect.)");

    }

}
